home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Emulators / v2600 / Source.lha / Source / misc.c < prev    next >
C/C++ Source or Header  |  1997-02-10  |  10KB  |  526 lines

  1. /*****************************************************************************
  2.  
  3.    This file is part of x2600, the Atari 2600 Emulator
  4.    ===================================================
  5.    
  6.    Copyright 1996 Alex Hornby. For contributions see the file CREDITS.
  7.  
  8.    This software is distributed under the terms of the GNU General Public
  9.    License. This is free software with ABSOLUTELY NO WARRANTY.
  10.    
  11.    See the file COPYING for Details.
  12.    
  13.    $Id: misc.c,v 1.4 1996/08/26 15:04:20 ahornby Exp $
  14.  
  15.    Tweaked by Matthew Stroup for Amiga v2600, January 27, 1997.
  16.  
  17. ******************************************************************************/
  18.  
  19. /*
  20.  
  21.  * This WAS part of the x64 Commodore 64 emulator.
  22.  *
  23.  * This file contains misc funtions to help debugging.
  24.  * Included are:
  25.  *      o Show numeric conversions
  26.  *      o Show CPU registers
  27.  *      o Show Stack contents
  28.  *      o Print binary number
  29.  *      o Print instruction hexas from memory
  30.  *      o Print instruction from memory
  31.  *      o Decode instruction
  32.  *      o Find effective address for operand
  33.  *      o Create a copy of string
  34.  *      o Move memory
  35.  *
  36.  * sprint_opcode returns mnemonic code of machine instruction.
  37.  * sprint_binary returns binary form of given code (8bit)
  38.  *
  39.  * Written by
  40.  *   Vesa-Matti Puro (vmp@lut.fi)
  41.  *   Jarkko Sonninen (sonninen@lut.fi)
  42.  *   Jouko Valta     (jopi@stekt.oulu.fi)
  43.  *
  44.  */
  45.  
  46. #include <stdio.h>
  47. #include <string.h>
  48. #include <stdlib.h>
  49. #include <ctype.h>
  50.  
  51. #include "cpu.h"
  52. #include "macro.h"
  53. #include "misc.h"
  54. #include "extern.h"
  55. #include "memory.h"
  56. #include "asm.h"
  57.  
  58. #define HEX 1
  59.  
  60. /*
  61.  *  Numeric evaluation with error checking
  62.  *
  63.  *   char   *s;         pointer to input string
  64.  *   int     level;     recursion level
  65.  *   int     mode;      flag: dec/hex mode
  66.  */
  67.  
  68. int
  69. sconv (char *s, int level, int mode)
  70. {
  71.   static char hexas[] = "0123456789abcdefg";
  72.   char *p = s;
  73.   int base = 0;
  74.   int result = 0, sign = 1;
  75.   int i = 0;
  76.  
  77.   if (!p)
  78.     return (0);
  79.  
  80.   switch (tolower (*p))
  81.     {
  82.     case '%':
  83.       p++;
  84.       base = 2;
  85.       break;
  86.  
  87.     case 'o':
  88.     case '&':
  89.       p++;
  90.       base = 8;
  91.       break;
  92.  
  93.     case 'x':
  94.     case '$':
  95.       p++;
  96.       base = 16;
  97.       break;
  98.  
  99.     case 'u':
  100.     case 'i':
  101.     case '#':
  102.       p++;
  103.       base = 10;
  104.       break;
  105.  
  106.     case '0':            /* 0x 0b 0d */
  107.       if (!*++p)
  108.     return ((mode & MODE_QUERY) ? 1 : 0);
  109.       if (!isdigit (*p))
  110.     return (sconv (p, level + 1, mode));
  111.  
  112.     case '1':
  113.     case '2':
  114.     case '3':
  115.     case '4':
  116.     case '5':
  117.     case '6':
  118.     case '7':
  119.     case '8':
  120.     case '9':
  121.       base = (mode & MODE_HEX) ? 16 : 10;
  122.       break;
  123.  
  124.     case 'a':
  125.     case 'c':
  126.     case 'e':
  127.     case 'f':
  128.       if (mode & MODE_HEX)
  129.     base = 16;
  130.       break;
  131.  
  132.     case 'b':            /* hex or binary */
  133.       if (mode & MODE_HEX)
  134.     base = 16;
  135.       else
  136.     {
  137.       base = 2;
  138.       p++;
  139.     }
  140.       break;
  141.  
  142.     case 'd':            /* hex or decimal */
  143.       if (mode & MODE_HEX)
  144.     base = 16;
  145.       else
  146.     {
  147.       base = 10;
  148.       p++;
  149.     }
  150.       break;
  151.  
  152.     default:
  153.       break;
  154.     }
  155.  
  156.   /*
  157.    * now p points to start of string to convert and base hold its base
  158.    * number 2, 8, 10 or 16
  159.    */
  160.  
  161.   if (!base)
  162.     return (0);
  163.  
  164.   if (*p == '-')
  165.     {
  166.       sign = -1;
  167.       p++;
  168.     }
  169.   while (tolower (*p))
  170.     {
  171.       for (i = 0; i < base; i++)
  172.     if (*p == hexas[i])
  173.       {
  174.         result = result * base + i;
  175.         break;
  176.       }
  177.       if (i >= base)
  178.     {
  179.       /* unknown char has occurred, return value or error */
  180.       if (strchr (",-+()", *p) || isspace (*p))
  181.         i = 0;
  182.       else if (!level && !(mode & MODE_QUERY))
  183.         printf ("Bad character near '%s'\n", p);
  184.  
  185.       break;
  186.     }
  187.       p++;
  188.     }
  189.   /* printf ("mode %02X  last %d base %d value %d\n",
  190.      mode, i, base, result); */
  191.  
  192.   /* return final value */
  193.   return ((mode & MODE_QUERY) ? (i < base) : result * sign);
  194. }
  195.  
  196.  
  197. /*
  198.  * Base conversions.
  199.  * (+) -%&#$
  200.  */
  201.  
  202. void
  203. show_bases (char *line, int mode)
  204. {
  205.   char buf[20];
  206.   int temparg = sconv (line, 0, mode);
  207.  
  208.   strcpy (buf, sprint_binary (UPPER (temparg)));
  209.   printf ("\n %17x x\n %17d d\n %17o o\n %s %s b\n\n",
  210.       temparg, temparg, temparg, buf,
  211.       sprint_binary (LOWER (temparg)));
  212. }
  213.  
  214.  
  215. /*
  216.  * show prints PSW and contents of registers.
  217.  */
  218.  
  219. void
  220. show (void)
  221. {
  222.     printf ("PC=%04X AC=%02X XR=%02X YR=%02X PF=%s SP=%02X %03X %3d %s\n",
  223.         (int) PC, (int) AC, (int) XR, (int) YR,
  224.         sprint_status (), (int) SP,
  225.         LOAD (PC), LOAD (PC), sprint_opcode (PC, 1));
  226. }
  227.  
  228.  
  229. void
  230. print_stack (UBYTE sp)
  231. {
  232.   int i;
  233.  
  234.   printf ("Stack: ");
  235.   for (i = 0x101 + sp; i < 0x200; i += 2)
  236.     printf ("%02X%02X  ", dbgRead (i + 1), dbgRead (i));
  237.   printf ("\n");
  238. }
  239.  
  240.  
  241. char
  242.  *
  243. sprint_binary (UBYTE code)
  244. {
  245.   static char bin[9];
  246.   int i;
  247.  
  248.   bin[8] = 0;            /* Terminator. */
  249.  
  250.   for (i = 0; i < 8; i++)
  251.     {
  252.       bin[i] = (code & 128) ? '1' : '0';
  253.       code <<= 1;
  254.     }
  255.  
  256.   return bin;
  257. }
  258.  
  259.  
  260. /* ------------------------------------------------------------------------- */
  261.  
  262. char
  263.  *
  264. sprint_ophex (ADDRESS p)
  265. {
  266.   static char hexbuf[20];
  267.   char *bp;
  268.   int j, len;
  269.  
  270.   len = clength[lookup[DLOAD (p)].addr_mode];
  271.   *hexbuf = '\0';
  272.   for (j = 0, bp = hexbuf; j < 3; j++, bp += 3)
  273.     {
  274.       if (j < len)
  275.     {
  276.       sprintf (bp, "%02X ", DLOAD (p + j));
  277.     }
  278.       else
  279.     {
  280.       strcat (bp, "   ");
  281.     }
  282.     }
  283.   return hexbuf;
  284. }
  285.  
  286.  
  287. /* sprint_opcode parameters:
  288.  
  289.  *      string          the name of the machine instruction
  290.  *      addr_mode       # describing used addressing mode, see "vmachine.h"
  291.  *      base            if 1==base => HEX, 0==base => DEC, see code
  292.  *      opcode          address of memory where machine instruction
  293.  *                      and argument are. First byte is unused, because
  294.  *                      it is the machine code and it is already known -
  295.  *                      string!
  296.  */
  297.  
  298.  
  299. char
  300.  *
  301. sprint_opcode (ADDRESS counter, int base)
  302. {
  303.   UBYTE x = DLOAD (counter);
  304.   UBYTE p1 = DLOAD (counter + 1);
  305.   UBYTE p2 = DLOAD (counter + 2);
  306.  
  307.   return sprint_disassembled (counter, x, p1, p2, base);
  308. }
  309.  
  310.  
  311. char
  312.  *
  313. sprint_disassembled (ADDRESS counter, UBYTE x, UBYTE p1, UBYTE p2, int base)
  314. {
  315.   char *string;
  316.   int addr_mode;
  317.   char *buffp;
  318.   static char buff[20];
  319.   int ival;
  320.  
  321.   ival = p1 & 0xFF;
  322.  
  323.   buffp = buff;
  324.   string = lookup[x].mnemonic;
  325.   addr_mode = lookup[x].addr_mode;
  326.  
  327.   sprintf (buff, "%s", string);    /* Print opcode. */
  328.   while (*++buffp);
  329.  
  330.   switch (addr_mode)
  331.     {
  332.       /*
  333.        * Bits 0 and 1 are usual marks for X and Y indexed addresses, i.e.
  334.        * if  bit #0 is set addressing mode is X indexed something and if
  335.        * bit #1 is set addressing mode is Y indexed something. This is not
  336.        * from MOS6502, but convention used in this program. See
  337.        * "vmachine.h" for details.
  338.        */
  339.  
  340.       /* Print arguments of the machine instruction. */
  341.  
  342.     case IMPLIED:
  343.       break;
  344.  
  345.     case ACCUMULATOR:
  346.       sprintf (buffp, " A");
  347.       break;
  348.  
  349.     case IMMEDIATE:
  350.       sprintf (buffp, ((base & HEX) ? " #$%02X" : " %3d"), ival);
  351.       break;
  352.  
  353.     case ZERO_PAGE:
  354.       sprintf (buffp, ((base & HEX) ? " $%02X" : " %3d"), ival);
  355.       break;
  356.  
  357.     case ZERO_PAGE_X:
  358.       sprintf (buffp, ((base & HEX) ? " $%02X,X" : " %3d,X"), ival);
  359.       break;
  360.  
  361.     case ZERO_PAGE_Y:
  362.       sprintf (buffp, ((base & HEX) ? " $%02X,Y" : " %3d,Y"), ival);
  363.       break;
  364.  
  365.     case ABSOLUTE:
  366.       ival |= ((p2 & 0xFF) << 8);
  367.       sprintf (buffp, ((base & HEX) ? " $%04X" : " %5d"), ival);
  368.       break;
  369.  
  370.     case ABSOLUTE_X:
  371.       ival |= ((p2 & 0xFF) << 8);
  372.       sprintf (buffp, ((base & HEX) ? " $%04X,X" : " %5d,X"), ival);
  373.       break;
  374.  
  375.     case ABSOLUTE_Y:
  376.       ival |= ((p2 & 0xFF) << 8);
  377.       sprintf (buffp, ((base & HEX) ? " $%04X,Y" : " %5d,Y"), ival);
  378.       break;
  379.  
  380.     case INDIRECT_X:
  381.       sprintf (buffp, ((base & HEX) ? " ($%02X,X)" : " (%3d,X)"), ival);
  382.       break;
  383.  
  384.     case INDIRECT_Y:
  385.       sprintf (buffp, ((base & HEX) ? " ($%02X),Y" : " (%3d),Y"), ival);
  386.       break;
  387.  
  388.     case ABS_INDIRECT:
  389.       ival |= ((p2 & 0xFF) << 8);
  390.       sprintf (buffp, ((base & HEX) ? " ($%04X)" : " (%5d)"), ival);
  391.       break;
  392.  
  393.     case RELATIVE:
  394.       if (0x80 & ival)
  395.     ival -= 256;
  396.       ival += counter;
  397.       ival += 2;
  398.       sprintf (buffp, ((base & HEX) ? " $%04X" : " %5d"), ival);
  399.       break;
  400.     }
  401.  
  402.   return buff;
  403. }
  404.  
  405.  
  406. int
  407. eff_address (ADDRESS counter, int step)
  408. {
  409.   int addr_mode, eff;
  410.   UBYTE x = LOAD (counter);
  411.   UBYTE p1 = 0;
  412.   ADDRESS p2 = 0;
  413.  
  414.  
  415.   addr_mode = lookup[x].addr_mode;
  416.  
  417.   switch (clength[addr_mode])
  418.     {
  419.     case 2:
  420.       p1 = LOAD (counter + 1);
  421.       break;
  422.     case 3:
  423.       p2 = LOAD (counter + 1) | (LOAD (counter + 2) << 8);
  424.       break;
  425.     }
  426.  
  427.   switch (addr_mode)
  428.     {
  429.  
  430.     case IMPLIED:
  431.     case ACCUMULATOR:
  432.       eff = -1;
  433.       break;
  434.  
  435.     case IMMEDIATE:
  436.       eff = -1;
  437.       break;
  438.  
  439.     case ZERO_PAGE:
  440.       eff = p1;
  441.       break;
  442.  
  443.     case ZERO_PAGE_X:
  444.       eff = (p1 + XR) & 0xff;
  445.       break;
  446.  
  447.     case ZERO_PAGE_Y:
  448.       eff = (p1 + YR) & 0xff;
  449.       break;
  450.  
  451.     case ABSOLUTE:
  452.       eff = p2;
  453.       break;
  454.  
  455.     case ABSOLUTE_X:
  456.       eff = p2 + XR;
  457.       break;
  458.  
  459.     case ABSOLUTE_Y:
  460.       eff = p2 + YR;
  461.       break;
  462.  
  463.     case ABS_INDIRECT:        /* loads 2-byte address */
  464.       eff = p2;
  465.       break;
  466.  
  467.     case INDIRECT_X:
  468.       eff = LOAD_ZERO_ADDR (p1 + XR);
  469.       break;
  470.  
  471.     case INDIRECT_Y:
  472.       eff = LOAD_ZERO_ADDR (p1) + YR;
  473.       break;
  474.  
  475.     case RELATIVE:
  476.       eff = REL_ADDR (counter + 2, p1);
  477.       break;
  478.  
  479.     default:
  480.       eff = -1;
  481.     }
  482.  
  483.   return eff;
  484. }
  485.  
  486.  
  487. /* ------------------------------------------------------------------------- */
  488.  
  489. char
  490.  *
  491. xstrdup (char *str)
  492. {
  493.   char *t = (char *) malloc (strlen (str) + 1);
  494.   strcpy (t, str);
  495.   return (t);
  496. }
  497.  
  498.  
  499. char
  500.  *
  501. strndup (char *str, int n)
  502. {
  503.   char *t = (char *) malloc (n + 1);
  504.   strncpy (t, str, n);
  505.   t[n] = '\0';
  506.   return (t);
  507. }
  508.  
  509.  
  510. void
  511. memmov (char *target, char *source, unsigned int length)
  512. {
  513.   if (target > source)
  514.     {
  515.       target += length;
  516.       source += length;
  517.       while (length--)
  518.     *--target = *--source;
  519.     }
  520.   else if (target < source)
  521.     {
  522.       while (length--)
  523.     *target++ = *source++;
  524.     }
  525. }
  526.